//
// Created by wangwanlong on 2024/6/17.
//

#ifndef MCGPP_VERTEX_PAIR_RATER_H
#define MCGPP_VERTEX_PAIR_RATER_H

#include "graph.h"
#include "typedef.h"
#include "fast_reset_flag_array.h"
#include "policies/rating_acceptance_policy.h"
//顶点对打分策略函数
//考虑重边匹配
namespace mcgpp {
  class VertexPairRating {
  public:
    VertexPairRating(IDType trgt, RatingType val, bool is_valid) :
            target(trgt),
            value(val),
            valid(is_valid) {}

    VertexPairRating() :
            target(std::numeric_limits<IDType>::max()),
            value(std::numeric_limits<RatingType>::min()),
            valid(false) {}

    VertexPairRating(const VertexPairRating &) = delete;

    VertexPairRating &operator=(const VertexPairRating &) = delete;

    VertexPairRating(VertexPairRating &&) = default;

    VertexPairRating &operator=(VertexPairRating &&) = delete;

    ~VertexPairRating() = default;

    IDType target;
    RatingType value;
    bool valid;
  };

  template<class AcceptancePolicy = BestRatingPreferringUnmatched<>>
  class VertexPairRater {
  public:

    VertexPairRater(ds::GenericGraph &graph) : _g(graph),
                                               _already_matched(graph.initialNumNodes()) {

    }

    //顶点打分函数:只考虑边的权重
    VertexPairRating rate(IDType u) {
      RatingType max_rating = std::numeric_limits<RatingType>::min();
      IDType target = -1;
      int cnt = 0;
      for (IDType e: _g.node(u).incidentNets()) {
        RatingType score = _g.edge(e).weight();
        //遍历边,选择一个最近顶点
        for (int i = _g.edge(e).firstEntry(); i != _g.edge(e).firstInvalidEntry(); ++i) {
          auto &v = _g._incidence_array[i];
          if (v != u && _g.partID(v) == _g.partID(u) &&
              AcceptancePolicy::accept(score, max_rating, (score == max_rating ? ++cnt : cnt),
                                       target, v, _already_matched)) {

            max_rating = score;
            target = v;
            if (score > max_rating)
              cnt = 0;
          }
        }
      }

      VertexPairRating ret;
      if (target != -1) {
        ret.target = target;
        ret.value = max_rating;
        ret.valid = true;
      }
      return ret;
    }


    WeightType nodeWeight(IDType u){
      WeightType weight = 0;
      switch (Context::instance().objMetric) {
        case ObjMetric::cut_num:
          weight = _g.node(u).total_edge_num;
          break;
        case ObjMetric::cut_weight:
          weight = _g.node(u).total_edge_weight;
          break;
        case ObjMetric::real:
          weight = _g.node(u).weight();
          break;
        default:
          ERROREXIT("error!");
      }
      return weight;
    }
    //打分函数2,新的计算公式 weight/(cu*cv),double转ll精度1e6吧
    VertexPairRating rate2(IDType u){
      const ll exp = 1000000;
      ll max_rating = std::numeric_limits<ll>::min();
      IDType target = -1;
      int cnt = 0;
      for (IDType e: _g.node(u).incidentNets()) {
        double score = _g.edge(e).weight();
        score /= static_cast<double>(nodeWeight(u));
        //遍历边,选择一个最近顶点
        for (int i = _g.edge(e).firstEntry(); i != _g.edge(e).firstInvalidEntry(); ++i) {
          auto &v = _g._incidence_array[i];
          if (v != u && _g.partID(v) == _g.partID(u)) {
            score /= static_cast<double>(v);
            ll tmp_rating = score * exp;

            if(AcceptancePolicy::accept(tmp_rating, max_rating, (tmp_rating == max_rating ? ++cnt : cnt),
                                     target, v, _already_matched)) {

              max_rating = tmp_rating;
              target = v;
              if (tmp_rating > max_rating)
                cnt = 0;
            }
          }
        }
      }

      VertexPairRating ret;
      if (target != -1) {
        ret.target = target;
        ret.value = max_rating;
        ret.valid = true;
      }
      return ret;
    }


    //标记顶点v被匹配
    void markAsMatched(const IDType v) {
      _already_matched.set(v, true);
    }

    void resetMatches() {
      _already_matched.reset();
    }


    ds::FastResetFlagArray<> _already_matched;//标识哪些以及被匹配了
    ds::GenericGraph &_g;
  };
}
#endif //MCGPP_VERTEX_PAIR_RATER_H
